package com.howie.parnote.util.security;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import com.howie.parnote.util.LogUtil;
import org.apache.log4j.Logger;
import org.apache.shiro.codec.Hex;

/**
 * DES Coder<br/>
 * secret key length: 56 bit, default: 56 bit<br/>
 * mode: ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128<br/>
 * padding: Nopadding/PKCS5Padding/ISO10126Padding/
 */
public class DESCoder {

	private static Logger logger = LogUtil.getLogger(DESCoder.class);


	/**
	 * 密钥算法
	 */
	private static final String KEY_ALGORITHM = "DES";

	/**
	 * 密钥
	 */
	public static final String MY_KEY = "DO522dongwx1881,hapshinimama88";

	private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
	private static Cipher cipher;

	//	private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/ISO10126Padding";

	private static Key k;

	static {

		byte[] key = MY_KEY.getBytes();
		try {
			k = toKey(key);
			cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
		} catch (Exception e) {
			logger.error("DESCoder初始化错误:", e);
		}
	}

	/**
	 * 初始化密钥
	 *
	 * @return byte[] 密钥
	 * @throws Exception
	 */
	public static byte[] initSecretKey() throws Exception {
		//返回生成指定算法的秘密密钥的 KeyGenerator 对象
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		//初始化此密钥生成器，使其具有确定的密钥大小
		kg.init(56);
		//生成一个密钥
		SecretKey secretKey = kg.generateKey();
		return secretKey.getEncoded();
	}

	/**
	 * 转换密钥
	 *
	 * @param key 二进制密钥
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		//实例化DES密钥规则
		DESKeySpec dks = new DESKeySpec(key);
		//实例化密钥工厂
		SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);
		//生成密钥
		SecretKey secretKey = skf.generateSecret(dks);
		return secretKey;
	}

	/**
	 * 加密
	 *
	 * @param data 待加密数据
	 * @param key  密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, Key key) throws Exception {
		return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
	}

	/**
	 * 加密
	 *
	 * @param data 待加密数据
	 * @param key  二进制密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
	}

	/**
	 * 加密
	 *
	 * @param data            待加密数据
	 * @param key             二进制密钥
	 * @param cipherAlgorithm 加密算法/工作模式/填充方式
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception {
		//还原密钥
		Key k = toKey(key);
		return encrypt(data, k, cipherAlgorithm);
	}

	/**
	 * 加密
	 *
	 * @param data            待加密数据
	 * @param key             密钥
	 * @param cipherAlgorithm 加密算法/工作模式/填充方式
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
		//使用密钥初始化，设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, key);
		//执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 解密
	 *
	 * @param data 待解密数据
	 * @param key  二进制密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
	}

	/**
	 * 解密
	 *
	 * @param data 待解密数据
	 * @param key  密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, Key key) throws Exception {
		return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
	}

	/**
	 * 解密
	 *
	 * @param data            待解密数据
	 * @param key             二进制密钥
	 * @param cipherAlgorithm 加密算法/工作模式/填充方式
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception {
		//还原密钥
		Key k = toKey(key);
		return decrypt(data, k, cipherAlgorithm);
	}

	/**
	 * 解密
	 *
	 * @param data            待解密数据
	 * @param key             密钥
	 * @param cipherAlgorithm 加密算法/工作模式/填充方式
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
		//使用密钥初始化，设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, key);
		//执行操作
		return cipher.doFinal(data);
	}

	private static String showByteArray(byte[] data) {
		if (null == data) {
			return null;
		}
		StringBuilder sb = new StringBuilder("{");
		for (byte b : data) {
			sb.append(b).append(",");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append("}");
		return sb.toString();
	}

	/**
	 * 对INT类型的ID字段进行加密
	 *
	 * @param id
	 * @return hex加密的字符串
	 * @throws Exception
	 */
	public static String getHexEncodeId(Integer id) throws Exception {
		return Hex.encodeToString(encrypt(id.toString().getBytes(), k));
	}

	/**
	 * 对HEX加密的ID字符串解密
	 *
	 * @param encodedId
	 * @return INT类型ID
	 * @throws Exception
	 */
	public static Integer getHexDecodeId(String encodedId) throws Exception {
		return Integer.parseInt(new String(decrypt(Hex.decode(encodedId), k)));
	}

	public static void main(String[] args) throws Exception {
//				byte[] key = initSecretKey();
		byte[] key = MY_KEY.getBytes();
//		System.out.println("key：" + showByteArray(key));

//		Key k = toKey(key);

		String data = "DES数据";
		Integer data2 = 1;
//		System.out.println("加密前数据: string:" + data);
//		System.out.println("加密前数据: byte[]:" + showByteArray(data.getBytes()));
//		System.out.println();
//		byte[] encryptData = encrypt(data2.toString().getBytes(), k);
//		System.out.println("加密后数据: byte[]:" + showByteArray(encryptData));
//		System.out.println("加密后数据: hexStr:" + Hex.encode(encryptData)+"---"+getHexEncodeId(data2)+"-----"+Hex.encode(encryptData));
//		System.out.println("解密后数据:" + new String(decrypt(Hex.decode(Hex.encode(encrypt(data2.toString().getBytes(), k))), k)));
//		System.out.println();
//		byte[] decryptData = decrypt(encryptData, k);
//		System.out.println("解密后数据: byte[]:" + showByteArray(decryptData));
//		System.out.println("解密后数据: string:" + new String(decryptData));
		String a = getHexEncodeId(532148621);
		System.out.println(a);
		int b = getHexDecodeId(a);
		System.out.println(b);
//		System.out.println(Hex.decode(getHexEncodeId(1)));
	}
}
